package com.example.auth.service.impl;

import com.example.auth.dto.DashboardStats;
import com.example.auth.dto.StudentProjectProgressDTO;
import com.example.auth.dto.SupervisorDashboardDTO;
import com.example.auth.entity.Project;
import com.example.auth.entity.Role;
import com.example.auth.entity.Task;
import com.example.auth.entity.User;
import com.example.auth.repository.ProjectRepository;
import com.example.auth.repository.RoleRepository;
import com.example.auth.repository.TaskRepository;
import com.example.auth.repository.UserRepository;
import com.example.auth.service.DashboardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DashboardServiceImpl implements DashboardService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private TaskRepository taskRepository;

    private DashboardStats.SystemInfo getSystemInfo() {
        DashboardStats.SystemInfo systemInfo = new DashboardStats.SystemInfo();
        Runtime runtime = Runtime.getRuntime();

        systemInfo.setJavaVersion(System.getProperty("java.version"));
        systemInfo.setOsName(System.getProperty("os.name"));
        systemInfo.setOsVersion(System.getProperty("os.version"));
        systemInfo.setTotalMemory(runtime.totalMemory());
        systemInfo.setFreeMemory(runtime.freeMemory());
        systemInfo.setAvailableProcessors(runtime.availableProcessors());

        return systemInfo;
    }

    private List<DashboardStats.UserInfo> getUserList() {
        List<DashboardStats.UserInfo> userList = new ArrayList<>();
        for (User user : userRepository.findAll()) {
            DashboardStats.UserInfo userInfo = new DashboardStats.UserInfo();
            userInfo.setId(user.getId());
            userInfo.setUsername(user.getUsername());
            userInfo.setRoles(user.getRoles().stream()
                    .map(Role::getName)
                    .collect(Collectors.toList()));
            userInfo.setCreateTime(user.getCreateTime() != null ?
                    user.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) :
                    "Unknown");
            userList.add(userInfo);
        }
        return userList;
    }

    @Override
    public DashboardStats getFullDashboardStats() {
        DashboardStats stats = new DashboardStats();

        // Get total number of users
        stats.setTotalUsers(userRepository.count());

        // Get role distribution
        Map<String, Long> roleDistribution = new HashMap<>();
        for (Role role : roleRepository.findAll()) {
            Long count = userRepository.countByRolesContaining(role);
            roleDistribution.put(role.getName(), count);
        }
        stats.setRoleDistribution(roleDistribution);

        // Get system information
        stats.setSystemInfo(getSystemInfo());

        // Get user list
        stats.setUserList(getUserList());

        return stats;
    }

    @Override
    public DashboardStats getBasicDashboardStats() {
        DashboardStats stats = new DashboardStats();

        // Normal users do not display user statistics
        stats.setTotalUsers(0L);

        // Does not include role distribution
        stats.setRoleDistribution(new HashMap<>());

        // Does not include user list
        stats.setUserList(new ArrayList<>());

        // Only return system information
        stats.setSystemInfo(getSystemInfo());

        return stats;
    }

    @Override
    public SupervisorDashboardDTO getSupervisorDashboardStats(Long supervisorId) {
        SupervisorDashboardDTO stats = new SupervisorDashboardDTO();

        // Find all students supervised by the supervisor
        List<User> students = userRepository.findAll().stream()
                .filter(user -> user.getRoles().stream().anyMatch(role -> "STUDENT".equals(role.getName())))
                .collect(Collectors.toList());

        // Set the total number of students
        stats.setStudentCount(students.size());

        int activeTodayCount = (int) students.stream()
                .filter(student -> "active".equals(student.getStatus()))
                .count();
        stats.setActiveToday(activeTodayCount);

        List<Task> allTasks = taskRepository.findBySupervisorId(supervisorId);
        List<Task> pendingTasks = allTasks.stream()
                .filter(task -> !task.getCompleted())
                .collect(Collectors.toList());
        stats.setPendingTasks(pendingTasks.size());

        LocalDateTime weekStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).minusDays(LocalDateTime.now().getDayOfWeek().getValue() - 1);
        int weeklyEventsCount = (int) pendingTasks.stream()
                .filter(task -> task.getCreateTime() != null && task.getCreateTime().isAfter(weekStart))
                .count();
        stats.setWeeklyEvents(weeklyEventsCount);

        List<StudentProjectProgressDTO> progressList = new ArrayList<>();

        List<Project> supervisorProjects = projectRepository.findBySupervisorId(supervisorId);

        for (Project project : supervisorProjects) {

            if (project.getAssigneeId() != null) {
                User student = userRepository.findById(project.getAssigneeId()).orElse(null);
                if (student != null) {
                    StudentProjectProgressDTO progressDTO = new StudentProjectProgressDTO();


                    progressDTO.setStudentId(student.getId());
                    progressDTO.setStudentName(student.getRealName() != null && !student.getRealName().isEmpty()
                            ? student.getRealName()
                            : student.getUsername());
                    progressDTO.setStudentNumber(student.getId().toString());

                    progressDTO.setProjectId(project.getId());
                    progressDTO.setProjectTitle(project.getTitle());
                    progressDTO.setProjectStatus(project.getStatus());

                    progressDTO.setDeadline(project.getEndTime());
                    progressDTO.setIsOverdue(project.getEndTime() != null &&
                            LocalDateTime.now().isAfter(project.getEndTime()));


                    List<Task> projectTasks = taskRepository.findByProjectId(project.getId());
                    int totalTasks = projectTasks.size();
                    progressDTO.setTotalTasks(totalTasks);


                    List<Task> completedTasks = projectTasks.stream()
                            .filter(Task::getCompleted)
                            .collect(Collectors.toList());
                    int completedTasksCount = completedTasks.size();
                    progressDTO.setCompletedTasks(completedTasksCount);


                    double progressPercentage = totalTasks > 0 ?
                            ((double) completedTasksCount / totalTasks) * 100 : 0;
                    progressDTO.setProgressPercentage(progressPercentage);

                    progressDTO.setStatus("active".equals(student.getStatus()) ?
                            "active" : "inactive");


                    if (!projectTasks.isEmpty()) {
                        Task latestTask = projectTasks.stream()
                                .max((t1, t2) -> t1.getUpdateTime().compareTo(t2.getUpdateTime()))
                                .orElse(null);
                        if (latestTask != null) {
                            progressDTO.setLastActivity(latestTask.getUpdateTime());
                            progressDTO.setLastActivityDescription("update: " + latestTask.getTitle());
                        }
                    }

                    progressList.add(progressDTO);
                }
            }
        }

        stats.setStudentProjectProgresses(progressList);


        List<SupervisorDashboardDTO.ActivityItem> activities = new ArrayList<>();


        for (Task task : pendingTasks.stream()
                .sorted((t1, t2) -> t2.getUpdateTime().compareTo(t1.getUpdateTime()))
                .limit(5)
                .collect(Collectors.toList())) {

            if (task.getAssigneeId() == null) {
                continue;
            }

            User assignee = userRepository.findById(task.getAssigneeId()).orElse(null);
            if (assignee != null) {
                SupervisorDashboardDTO.ActivityItem activity = new SupervisorDashboardDTO.ActivityItem();

                // Set activity information
                activity.setTitle("Task Status Update from Student " + assignee.getUsername());
                activity.setDescription(assignee.getUsername() + (task.getCompleted() ? " completed " : " updated ") + "《" + task.getTitle() + "》");

                // Format time
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
                LocalDateTime updateTime = task.getUpdateTime();
                LocalDateTime now = LocalDateTime.now();

                String timeDisplay;
                if (updateTime.toLocalDate().equals(now.toLocalDate())) {
                    timeDisplay = "Today " + updateTime.format(DateTimeFormatter.ofPattern("HH:mm"));
                } else if (updateTime.toLocalDate().equals(now.toLocalDate().minusDays(1))) {
                    timeDisplay = "Yesterday " + updateTime.format(DateTimeFormatter.ofPattern("HH:mm"));
                } else {
                    timeDisplay = updateTime.format(formatter);
                }

                activity.setTime(timeDisplay);
                activity.setType("Task Update");

                activities.add(activity);
            }
        }

        stats.setRecentActivities(activities);

        return stats;
    }
}